package com.dx.as.download;

import android.util.Log;

import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.SocketException;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;

import static com.dx.as.download.DownloadManager.STATE_DOWNING;
import static com.dx.as.download.DownloadManager.STATE_EXISTS;
import static com.dx.as.download.DownloadManager.STATE_FAILED;
import static com.dx.as.download.DownloadManager.STATE_FINISH;
import static com.dx.as.download.DownloadManager.STATE_NETWORK_DISSCONECTED;
import static com.dx.as.download.DownloadManager.STATE_PAUSE;

/**
 * Created by jwaoo on 2018/1/24.
 */

public class DownloadTask {
    private DownloadInfo info;
    private DownloadTask downloadTask;
    private OnDownloadListener onDownloadListener;
    private HttpUtil httpUtil;
    private boolean isCancel = false;
    private static int faildNum = 0;
    private final static int FAILD_MAX_DOWNLOAD_NUM = 20;
    public DownloadTask(DownloadInfo info, OnDownloadListener listener) {
        this.info = info;
        this.onDownloadListener = listener;
        this.httpUtil = HttpUtil.getInstance();
        downloadTask = this;
    }

    public DownloadTask(DownloadInfo info){
        this(info,null);
    }

    public void setOnDownloadListener(OnDownloadListener onDownloadListener) {
        this.onDownloadListener = onDownloadListener;
    }

    public String getKey() {
        return this.info.getKey();
    }

    //开始下载
    public void start() throws Exception{
        if (info.getState() == STATE_DOWNING || info.getState() == STATE_FINISH || info.getState() == STATE_PAUSE) return;
        isCancel = false;
        download();
    }

    //下载
    public void download(){
        try{
            info.setState(STATE_DOWNING);

            File file = new File(info.getFileDir(),info.getFileName());
            if (file.exists()) {
                info.setState(STATE_EXISTS);
                if (onDownloadListener != null){
                    onDownloadListener.onFileExists();
                }
                return;
            }

            final File cacheFile = new File(this.info.getFileDir(), info.getFileName()+".cache");
            if (!cacheFile.getParentFile().exists()) cacheFile.getParentFile().mkdirs();
            final RandomAccessFile cacheAccessFile = new RandomAccessFile(cacheFile, "rwd");
            int startIndex = 0;
            if (cacheFile.exists()) {// 如果文件存在
                String startIndexStr = cacheAccessFile.readLine();
                try {
                    startIndex = startIndexStr == null ? 0 : Integer.parseInt(startIndexStr);//重新设置下载起点
                } catch (NumberFormatException e) {
                    e.printStackTrace();
                }
            }
            final long offset = startIndex;
            Log.e("======",info.getFileName()+"   :   "+offset);
            httpUtil.downloadFileByRange(info.getUrl(), startIndex, new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    if (onDownloadListener != null)
                        onDownloadListener.onDownloadFailed();
                    e.printStackTrace();
                }
                @Override
                public void onResponse(Call call, Response response){
                    InputStream is = null;
                    try{
                        if (offset >= 0 && response.code() != 200) {// 206：请求部分资源成功码，表示服务器支持断点续传
                            DownloadManager.downloadFailed(downloadTask);
                            info.setState(STATE_FAILED);
                            Log.e("DownloadTask","下载失败 ： "+response.code());
                            return;
                        }
                        long size = response.body().contentLength();
                        File mTmpFile = new File(info.getFileDir(), info.getFileName()+".tmp");
                        RandomAccessFile tmpAccessFile = new RandomAccessFile(mTmpFile, "rw");
                        tmpAccessFile.setLength(size);
                        is = response.body().byteStream();//获取流
                        tmpAccessFile.seek(offset);// 文件写入的开始位置.
                 /*  将网络流中的文件写入本地*/
                        byte[] buffer = new byte[1024 << 2];
                        int length = -1;
                        int total = 0;// 记录本次下载文件的大小
                        long progress = 0;
                        while ((length = is.read(buffer)) > 0) {//读取流
                            if (isCancel){
                                close(cacheAccessFile,is,response.body());
                                if (onDownloadListener != null)
                                    onDownloadListener.onStop();
                                DownloadManager.onDownloadStop(downloadTask);
                                return;
                            }
                            tmpAccessFile.write(buffer, 0, length);
                            total += length;
                            progress = offset + total;
                            //将该线程最新完成下载的位置记录并保存到缓存数据文件中
                            //建议转成Base64码，防止数据被修改，导致下载文件出错（若真有这样的情况，这样的朋友可真是无聊透顶啊）
                            cacheAccessFile.seek(0);
                            cacheAccessFile.write((progress + "").getBytes("UTF-8"));
                            Log.d("download","key = "+info.getFileName()+"  progress = "+progress +"  total = "+size);
                            if (onDownloadListener != null)
                                onDownloadListener.onDownProgress(progress,size);
                        }

                        mTmpFile.renameTo(new File(info.getFileDir(), info.getFileName()));
                        DownloadManager.downloadFinish(downloadTask);
                        info.setState(STATE_FINISH);
                        if (onDownloadListener != null)
                            onDownloadListener.onSuccess();

                    }catch (SocketException e){
                        DownloadManager.downloadStopByNetWork(downloadTask);
                        info.setState(STATE_NETWORK_DISSCONECTED);
                    }catch (Exception ex){
                        faildNum++;
                        if (faildNum == FAILD_MAX_DOWNLOAD_NUM ){
                            if (onDownloadListener != null)
                                onDownloadListener.onDownloadFailed();
                            info.setState(STATE_FAILED);
                        }
                        download();
                        ex.printStackTrace();
                    }finally {
                        try{
                            close(cacheAccessFile,is,response.body());
                            if (info.getState() == STATE_FINISH)
                                cleanFile(cacheFile);
                        }catch (Exception ex){
                            ex.printStackTrace();
                        }
                    }
                }
            });
        }catch (Exception ex){
            ex.printStackTrace();
        }

    }

    private void cleanFile(File... files) {
        for (int i = 0, length = files.length; i < length; i++) {
            if (null != files[i])
                files[i].delete();
        }
    }

    private void close(Closeable... closeables) {
        int length = closeables.length;
        try {
            for (int i = 0; i < length; i++) {
                Closeable closeable = closeables[i];
                if (null != closeable)
                    closeables[i].close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            for (int i = 0; i < length; i++) {
                closeables[i] = null;
            }
        }
    }

    //暂停
    public void pause(){
        isCancel = true;
        info.setState(STATE_PAUSE);
    }


    public DownloadInfo getInfo() {
        return info;
    }
}
